package com.example.demo.excel;


import com.example.demo.annotation.JoinField;
import com.example.demo.entity.Room;
import com.example.demo.entity.User;
import com.example.demo.view.ModelItem;
import lombok.SneakyThrows;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 封装阿里的Excel导出
 */
public class ExcelUtil {

    public static void write(Class clazz, HttpServletResponse response, List datas) {
        XSSFWorkbook wb = new XSSFWorkbook();
        Sheet sheet = wb.createSheet();
        setDatas(sheet, clazz, datas);
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
            wb.write(response.getOutputStream());
            response.getOutputStream().flush();
            response.getOutputStream().close();
            wb.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @SneakyThrows
    public static List<Object> read(Class clazz, MultipartFile file) {
        XSSFWorkbook wb = new XSSFWorkbook(file.getInputStream());
        XSSFSheet sheet = wb.getSheetAt(0);
        //初始化值Map
        List<Map> list = new ArrayList<>();
        //将excel的值都存入map
        Row head = sheet.getRow(0);
        //sheet.getLastRowNum() 下标数
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            Map map = new HashMap();
            //row.getLastCellNum() 比下标多一
            for (int j = 0; j < row.getLastCellNum(); j++) {
                String key = head.getCell(j).getStringCellValue();
                if (row.getCell(j)==null) {
                    map.put(key, null);
                } else {
                    map.put(key, row.getCell(j).getStringCellValue());
                }

            }
            list.add(map);
        }
        List resList = new ArrayList();
        //反射转换成实体类
        for (Map<String, Object> map : list) {
            Object o = clazz.newInstance();
            for (Field field : clazz.getDeclaredFields()) {
                ModelItem modelItem = field.getAnnotation(ModelItem.class);

                //不可编辑或者不存在
                if (modelItem == null || modelItem.edit() == false || !map.containsKey(modelItem.title())) {
                    continue;
                }
                Object res = map.get(modelItem.title());
                if(res==null){
                    continue;
                }
                if(res.equals("")&&field.getType()!=String.class){
                    continue;
                }
                String methodName = String.format("set%s", StringUtils.capitalize(field.getName()));
                //时间处理
                if (res != null && !res.equals("") && field.getType() == Date.class) {
                    SimpleDateFormat format = new SimpleDateFormat(modelItem.format());
                    res = format.parse((String) res);
                }

                if(field.getType()==Integer.class){
                    //枚举处理
                    if (modelItem.options().length > 0) {
                        res = getIndexFromOptions(modelItem.options(), (String) res);
                    }else {
                        res = Integer.valueOf((String) res);
                    }
                }

                if(field.getType()==Long.class){
                    //枚举处理
                    if (modelItem.options().length > 0) {
                        res = getIndexFromOptions(modelItem.options(), (String) res);
                    }else {
                        res = Long.valueOf((String) res);
                    }
                }
                clazz.getDeclaredMethod(methodName, field.getType()).invoke(o, res);
            }
            resList.add(o);
        }
        return resList;
    }


    public static Integer getIndexFromOptions(String[] strs, String str) {
        Integer res = 0;
        for (int i = 0; i < strs.length; i++) {
            if (str == strs[i]) {
                res = i;
            }
        }
        return res;
    }


    private static void setDatas(Sheet sheet, Class clazz, List<Object> datas) {
        for (int i = 0; i < datas.size(); i++) {
            Row headRow = null;
            Row row;
            if (i == 0) {
                headRow = sheet.createRow(i);
            }
            row = sheet.createRow(i + 1);
            Integer cellIdx = 0;
            setData(clazz, datas.get(i), row, headRow, cellIdx);
        }
    }

    @SneakyThrows
    public static void setData(Class clazz, Object data, Row row, Row headRow, Integer cellIdx) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            JoinField joinField = field.getAnnotation(JoinField.class);
            if (joinField != null) {
                setData(field.getType(), field.get(data), row, headRow, cellIdx);
            }
            //跳过
            ModelItem modelItem = field.getAnnotation(ModelItem.class);
            if (modelItem == null || modelItem.excel() == false) {
                continue;
            }
            //设置值
            if (headRow != null) {
                headRow.createCell(cellIdx).setCellValue(modelItem.title());
            }
            setCellValue(row.createCell(cellIdx), field, data, modelItem);
            cellIdx++;
            //
        }
    }

    @SneakyThrows
    public static void setCellValue(Cell cell, Field field, Object o, ModelItem modelItem) {
        if (o == null || field.get(o) == null) return;
        if (field.getType() == Date.class) {
            Date date = (Date) field.get(o);
            if (date == null) return;
            SimpleDateFormat dateFormat = new SimpleDateFormat(modelItem.format());
            cell.setCellValue(dateFormat.format(date));
        } else {
            if (modelItem.options() != null && modelItem.options().length > 0) {
                cell.setCellValue(modelItem.options()[(int) field.get(o)]);
            } else {
                cell.setCellValue(field.get(o).toString());
            }

        }
    }


}
